using System;
using System.Diagnostics;
using System.IO;
using HappyTemplate;
using NUnit.Framework;

namespace HappyTemplate.Tests
{
	public class TestFixtureHelper
	{
		internal SourceErrorCollection _sourceErrors;
		protected internal TemplateContext _context;

		internal TemplateLexer NewLexer(string textToLex)
		{
			string template = "testTemplate() <{" + textToLex + "}>";
			StringReader streamReader = new StringReader(template);
			_sourceErrors = new SourceErrorCollection();
			TemplateLexer retval = new TemplateLexer(new InputReader(streamReader, "string"), _sourceErrors);

			NextTokenAssert(retval, TokenType.Identifier, "testTemplate");
			NextTokenAssert(retval, TokenType.OpenParen);
			NextTokenAssert(retval, TokenType.CloseParen);
			NextTokenAssert(retval, TokenType.BeginTemplate);

			return retval;
		}

		internal Template ParseTemplate(string textToParse)
		{
			return ParseTemplate("", textToParse);
		}

		protected internal Template ParseTemplate(string paramList, string textToParse)
		{
			string template = "testTemplate(" + paramList + ") <{" + textToParse + "}>";
			StringReader streamReader = new StringReader(template);
			_sourceErrors = new SourceErrorCollection();
			TemplateLexer lexer = new TemplateLexer(new InputReader(streamReader, "string"), _sourceErrors);
			TemplateParser parser = new TemplateParser(lexer, _sourceErrors);
			try
			{
				TemplateSet set = parser.Parse();
				AssertNoErrors();
				_context = set.Context;
				return set.GetTemplate("testTemplate");
			}
			catch (AbortParseException)
			{
				foreach (SourceError error in _sourceErrors)
					Debug.Print(error.ToString());
					Assert.Fail("Caught AbortParseException");
				return null;
			}
		}

		protected internal Template ParseTemplateNoCatch(string textToParse)
		{
			return ParseTemplateNoCatch("", textToParse);
		}

		protected internal Template ParseTemplateNoCatch(string paramList, string textToParse)
		{
			string template = "testTemplate(" + paramList + ") <{" + textToParse + "}>";
			StringReader streamReader = new StringReader(template);
			_sourceErrors = new SourceErrorCollection();
			TemplateLexer lexer = new TemplateLexer(new InputReader(streamReader, "string"), _sourceErrors);
			TemplateParser parser = new TemplateParser(lexer, _sourceErrors);
			TemplateSet set = parser.Parse();
			_context = set.Context;
			return set.GetTemplate("testTemplate");
		}

		protected internal TemplateSet ParseTemplateSet(string template)
		{
			StringReader streamReader = new StringReader(template);
			_sourceErrors = new SourceErrorCollection();
			TemplateLexer lexer = new TemplateLexer(new InputReader(streamReader, "string"), _sourceErrors);
			TemplateParser parser = new TemplateParser(lexer, _sourceErrors);
			try
			{
				TemplateSet ts = parser.Parse();
				AssertNoErrors();
				_context = ts.Context;
				return ts;
			}
			catch (AbortParseException ex)
			{
				Debug.Print("{0} source error(s)	:", _sourceErrors.Count);
				foreach (SourceError error in _sourceErrors)
					Debug.Print(error.ToString());

				Debug.Print("Parsing aborted at: " + ex.Location);
				Debug.Print("Call Stack:");
				Debug.Print(ex.StackTrace	);

				Assert.Fail("Caught AbortParseException");
				return null;
			}
		}

		protected internal TemplateSet ParseTemplateSetNoCatch(string template)
		{
			StringReader streamReader = new StringReader(template);
			_sourceErrors = new SourceErrorCollection();
			TemplateLexer lexer = new TemplateLexer(new InputReader(streamReader, "string"), _sourceErrors);
			TemplateParser parser = new TemplateParser(lexer, _sourceErrors);
			TemplateSet ts = parser.Parse();
			_context = ts.Context;
			return ts;
		}

		protected internal string HandledWriteTemplate(Template template)
		{
			try
			{
				StringWriter sw = new StringWriter();
				template.Execute(_context, sw);
				return sw.ToString();

			}
			catch (TemplateExecutionException ex)
			{
				Debug.Print(ex.ToString());
				Exception inner = ex.InnerException;
				while(inner != null)
				{
					Debug.Print("Inner ({0}):  {1}", inner.GetType(), inner.Message);
					inner = inner.InnerException;
				}
				Assert.Fail("Caught TemplateExecutionException");
				return null;
			}
		}
		protected internal string HandledWriteTemplate(string template)
		{
			Template t = ParseTemplate(template);
			return HandledWriteTemplate(t);
		}


		protected internal string WriteTemplate(string template)
		{
			Template t = ParseTemplate(template);
			return WriteTemplate(t, _context);
		}

		protected internal static string WriteTemplate(Template template, TemplateContext context)
		{
			StringWriter sw = new StringWriter();
			template.Execute(context, sw);
			return sw.ToString();
		}

		protected internal static void NextTokenAssert(TemplateLexer lexer, TokenType expectedTokenType)
		{
			Token t = lexer.NextToken();
			Assert.AreEqual(expectedTokenType, t.TokenType, "Token Text:  {0}", t.Text);
		}

		protected internal static Token NextTokenAssert(TemplateLexer lexer, TokenType expectedTokenType, string expectedText)
		{
			Token t = lexer.NextToken();
			Assert.AreEqual(expectedTokenType, t.TokenType, "Token Text:  {0}", t.Text);
			Assert.AreEqual(expectedText, t.Text);
			return t;
		}

		protected internal void AssertNoErrors()
		{
			foreach (SourceError error in _sourceErrors)
				Debug.Print(error.ToString());

			Assert.AreEqual(0, _sourceErrors.Count, "Wanted zero errors but {0} were found.", _sourceErrors.Count);
		}
	}
}
